/*
 * Copyright 2013 JROSE
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.jrose.core.util;

import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.codehaus.jackson.map.DeserializationConfig;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.SerializationConfig;
import org.codehaus.jackson.map.annotate.JsonSerialize;
import org.codehaus.jackson.type.JavaType;

import java.util.Map;

/**
 * Json related utilities.
 *
 * @author Xiaohai Zhang
 * @since 2013-08-19 15:25
 */
@Slf4j
@NoArgsConstructor(access = AccessLevel.PRIVATE)
abstract public class JsonUtils {
    public static final String EMPTY_JSON_ARRAY = "[]";
    public static final String EMPTY_JSON_OBJECT = "{}";

    private static final ObjectMapper mapper;
    private static final JavaType mapJavaType;

    static {
        mapper = new ObjectMapper();
        mapper.getSerializationConfig().withSerializationInclusion(JsonSerialize.Inclusion.ALWAYS);
        mapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        mapper.configure(DeserializationConfig.Feature.FAIL_ON_NUMBERS_FOR_ENUMS, true);
        mapper.configure(SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS, false);

        mapJavaType = constructParametricType(Map.class, String.class, Object.class);
    }

    public static Map<String, Object> fromJson(String content) {
        return fromJson(content, mapJavaType);
    }

    public static <T> T fromJson(String content, Class<T> valueType) {
        if (StringUtils.isBlank(content)) {
            return null;
        }
        try {
            return mapper.readValue(content, valueType);
        } catch (Exception ex) {
            return null;
        }
    }

    @SuppressWarnings("unchecked")
    public static <T> T fromJson(String content, JavaType valueType) {
        if (StringUtils.isBlank(content)) {
            return null;
        }
        try {
            return (T) mapper.readValue(content, valueType);
        } catch (Exception ex) {
            return null;
        }
    }

    public static String toJson(Object value, boolean usePrettyPrinter) {
        try {
            if (usePrettyPrinter) {
                return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(value);
            } else {
                return mapper.writeValueAsString(value);
            }
        } catch (Exception ex) {
            return null;
        }
    }

    public static String toJson(Object value) {
        return toJson(value, false);
    }

    public static JavaType constructParametricType(Class<?> parametrized, Class<?>... parameterClasses) {
        return mapper.getTypeFactory().constructParametricType(parametrized, parameterClasses);
    }
}
